package com.frank.loadinglibrary.common.element;

import com.frank.loadinglibrary.base.baseanimations.BaseAnimationController;
import com.frank.loadinglibrary.base.baseelement.BaseElement;
import com.frank.loadinglibrary.base.baseelement.IComponentCallback;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;

import java.util.ArrayList;

/**
 * @author SUQI
 * @date 2021/6/2
 * @description
 **/
public class BallSwingElement extends BaseElement implements BaseAnimationController.IAnimationController<AnimatorValue> {

    private static final float CIRCLE_ALPHA = 1f;
    private static final float OVA_ALPHA = 0.25f;
    private Paint mPaint;
    private int mBallCount;
    private float mBallRadius;
    private float mBallCenterY;
    private float mBallSideOffsets;
    private boolean isFirstBallSwing = true;
    private float rotateAngle = 0;
    private final RectFloat mOvalRect = new RectFloat();

    private BallSwingElement(IComponentCallback callback) {
        this.callback = callback;
    }

    @Override
    public ArrayList<AnimatorValue> onCreateAnimators() {
        ArrayList<AnimatorValue> list = new ArrayList<>();
        AnimatorValue animatorValue = new AnimatorValue();
        animatorValue.setDuration(2000);
        animatorValue.setLoopedCount(Animator.INFINITE);
        animatorValue.setValueUpdateListener((animatorValue1, v) -> {
            rotateAngle = (v > 0.5f ? 1 - v : v) * 60;
            callback.reflushComponent();
        });
        animatorValue.setLoopedListener(animator -> isFirstBallSwing = !isFirstBallSwing);
        animatorValue.start();
        list.add(animatorValue);
        return list;
    }

    @Override
    public void onAnimationReset() {
        //do nothing because donot need to reset animation params
    }

    @Override
    public void initPaint() {
        super.initPaint();
        mPaint = new Paint();
        mPaint.setStyle(Paint.Style.FILL_STYLE);
        mPaint.setColor(Color.WHITE);
        mPaint.setAntiAlias(true);
    }

    @Override
    public void draw(Canvas canvas) {
        super.draw(canvas);
        mBallCenterY = getHeight() / 2f;
        mBallSideOffsets = (getWidth() - mBallRadius * 2 * mBallCount) / 2;
        for (int i = 1; i < mBallCount - 1; i++) {
            mPaint.setAlpha(CIRCLE_ALPHA);
            canvas.drawCircle(mBallRadius * (i * 2 + 1) + mBallSideOffsets, mBallCenterY, mBallRadius, mPaint);
            mPaint.setAlpha(OVA_ALPHA);
            setRect(mOvalRect, mBallRadius * (i * 2) + mBallSideOffsets, mBallCenterY + mBallRadius,
                    mBallRadius * (i * 2 + 2) + mBallSideOffsets, mBallCenterY + 2 * mBallRadius);
            canvas.drawOval(mOvalRect, mPaint);
        }
        if (isFirstBallSwing) {
            //画最后一个小球
            mPaint.setAlpha(CIRCLE_ALPHA);
            canvas.drawCircle(mBallRadius * ((mBallCount - 1) * 2 + 1) + mBallSideOffsets, mBallCenterY, mBallRadius, mPaint);
            mPaint.setAlpha(OVA_ALPHA);
            setRect(mOvalRect, mBallRadius * ((mBallCount - 1) * 2) + mBallSideOffsets, mBallCenterY + mBallRadius,
                    mBallRadius * ((mBallCount - 1) * 2 + 2) + mBallSideOffsets, mBallCenterY + 2 * mBallRadius);
            canvas.drawOval(mOvalRect, mPaint);
        } else {
            //画第一个小球
            mPaint.setAlpha(CIRCLE_ALPHA);
            canvas.drawCircle(mBallRadius + mBallSideOffsets, mBallCenterY, mBallRadius, mPaint);
            mPaint.setAlpha(OVA_ALPHA);
            setRect(mOvalRect, mBallSideOffsets, mBallCenterY + mBallRadius,
                    mBallRadius * 2 + mBallSideOffsets, mBallCenterY + 2 * mBallRadius);
            canvas.drawOval(mOvalRect, mPaint);
        }
        canvas.save();
        mPaint.setAlpha(CIRCLE_ALPHA);
        if (isFirstBallSwing) {
            canvas.rotate(rotateAngle, getWidth() / 2f, getHeight() / 2f - 80);
            canvas.drawCircle(mBallRadius + mBallSideOffsets, mBallCenterY, mBallRadius, mPaint);
        } else {
            canvas.rotate(-rotateAngle, getWidth() / 2f, getHeight() / 2f - 80);
            canvas.drawCircle(mBallRadius * ((mBallCount - 1) * 2 + 1) + mBallSideOffsets, mBallCenterY, mBallRadius, mPaint);
        }
        canvas.restore();
    }

    public void setRect(RectFloat rect, float left, float top, float right, float bottom) {
        rect.left = left;
        rect.top = top;
        rect.right = right;
        rect.bottom = bottom;
    }

    @Override
    public BaseAnimationController.IAnimationController initAnimationController() {
        return this;
    }

    public void apply(BallSwingBuilder builder) {
        this.mBallCount = builder.mBallCount;
        this.mBallRadius = builder.mBallRadius;
    }

    public static class BallSwingBuilder {
        private static final float DEFAULT_RADIUS = 15f;

        private IComponentCallback iComponentCallback;
        private int mBallCount = 4;
        private float mBallRadius = DEFAULT_RADIUS;

        public BallSwingBuilder(IComponentCallback iComponentCallback) {
            this.iComponentCallback = iComponentCallback;
        }

        public BallSwingBuilder setBallCount(int mBallCount) {
            this.mBallCount = mBallCount;
            return this;
        }

        public BallSwingBuilder setBallRadius(float mBallRadius) {
            this.mBallRadius = mBallRadius;
            return this;
        }

        public BallSwingElement build() {
            BallSwingElement ballSwingElement = new BallSwingElement(iComponentCallback);
            ballSwingElement.apply(this);
            return ballSwingElement;
        }
    }
}
